/**
 *
 */
package jp.seraph.jsade.effector;

import java.util.Iterator;

import jp.seraph.jsade.message.MessageUtil;
import jp.seraph.jsade.sexpression.DefaultLeaf;
import jp.seraph.jsade.sexpression.DefaultNode;
import jp.seraph.jsade.sexpression.ExpressionVisitor;
import jp.seraph.jsade.sexpression.Leaf;
import jp.seraph.jsade.sexpression.Node;
import jp.seraph.jsade.sexpression.SExpression;

/**
 * エフェクタのデフォルト実装です
 */
public class DefaultEffector implements Effector {
    public DefaultEffector(Node aBaseNode, EffectorKind aKind) throws IllegalArgumentException {
        checkBaseNode(aBaseNode);
        init(aBaseNode, aKind);
    }

    /**
     * (aKind.toString aValue) となるエフェクタを作成します。
     * 
     * @param aKind
     * @param aValue
     */
    public DefaultEffector(EffectorKind aKind, int aValue) {
        DefaultNode tBaseNode = new DefaultNode();
        tBaseNode.addChild(aKind.toString());
        tBaseNode.addChild(Integer.toString(aValue));

        init(tBaseNode, aKind);
    }

    /**
     * エフェクタの種類とそのパラメータをintで受け取ってエフェクタを作成する。
     * 
     * 以下のような平坦なエフェクタが作成されます。 (aKind.toString() aValues[0] aValues[1] ...)
     * 
     * 複雑な構造を持つエフェクタを作成する場合は、ベースとなるノードを受けとるコンストラクタを使用してください。
     * 
     * @param aKind
     * @param aValues
     */
    public DefaultEffector(EffectorKind aKind, int... aValues) {
        DefaultNode tBaseNode = new DefaultNode();
        tBaseNode.addChild(aKind.toString());

        for (int tDouble : aValues) {
            tBaseNode.addChild(Integer.toString(tDouble));
        }

        init(tBaseNode, aKind);
    }

    /**
     * エフェクタの種類とそのパラメータをdoubleで受け取ってエフェクタを作成する。
     * 
     * 以下のような平坦なエフェクタが作成されます。 (aKind.toString() aValues[0] aValues[1] ...)
     * 
     * 複雑な構造を持つエフェクタを作成する場合は、ベースとなるノードを受けとるコンストラクタを使用してください。
     * 
     * @param aKind
     * @param aValues
     */
    public DefaultEffector(EffectorKind aKind, double... aValues) {
        DefaultNode tBaseNode = new DefaultNode();
        tBaseNode.addChild(aKind.toString());

        for (double tDouble : aValues) {
            tBaseNode.addChild(Double.toString(tDouble));
        }

        init(tBaseNode, aKind);
    }

    /**
     * (aKind.toString aValue) となるエフェクタを作成します。
     * 
     * @param aKind
     * @param aValue
     */
    public DefaultEffector(EffectorKind aKind, double aValue) {
        DefaultNode tBaseNode = new DefaultNode();
        tBaseNode.addChild(aKind.toString());
        tBaseNode.addChild(Double.toString(aValue));

        init(tBaseNode, aKind);
    }

    /**
     * エフェクタの種類とそのパラメータをStringで受け取ってエフェクタを作成する。
     * 
     * 以下のような平坦なエフェクタが作成されます。 (aKind.toString() aValues[0] aValues[1] ...)
     * 
     * 複雑な構造を持つエフェクタを作成する場合は、ベースとなるノードを受けとるコンストラクタを使用してください。
     * 
     * @param aKind
     * @param aValues
     */
    public DefaultEffector(EffectorKind aKind, String... aValues) {
        DefaultNode tBaseNode = new DefaultNode();
        tBaseNode.addChild(new DefaultLeaf(aKind.toString()));

        for (String tStr : aValues) {
            tBaseNode.addChild(new DefaultLeaf(tStr));
        }

        init(tBaseNode, aKind);
    }

    /**
     * (aKind.toString aValue) となるエフェクタを作成します。
     * 
     * @param aKind
     * @param aValue
     */
    public DefaultEffector(EffectorKind aKind, String aValue) {
        DefaultNode tBaseNode = new DefaultNode();
        tBaseNode.addChild(aKind.toString());
        tBaseNode.addChild(aValue);

        init(tBaseNode, aKind);
    }

    /**
     * 初期化を行わないコンストラクタ このクラスを継承したクラスがこのコンストラクタを呼び出す場合、必ずinitメソッドによる初期化を行うこと。
     * 
     */
    protected DefaultEffector() {
        // 何もしない
    }

    protected void init(Node aBaseNode, EffectorKind aKind) {
        mBaseNode = aBaseNode;
        mKind = aKind;
    }

    protected void checkBaseNode(Node aBaseNode) throws IllegalArgumentException {
        if (aBaseNode.childCount() == 0)
            throw new IllegalArgumentException(MessageUtil.noChildNode());
        if (aBaseNode.getChild(0).isNode())
            throw new IllegalArgumentException(MessageUtil.firstChildMustBeLeaf());

    }

    private Node mBaseNode;
    private EffectorKind mKind;

    /**
     * 
     * @see jp.seraph.jsade.effector.Effector#getKind()
     */
    public EffectorKind getKind() {
        return mKind;
    }

    /**
     * 
     * @see jp.seraph.jsade.effector.Effector#getName()
     */
    public String getName() {
        return mBaseNode.getChildAsLeaf(0).getValue();
    }

    /**
     * 
     * @see jp.seraph.jsade.sexpression.Node#addChild(jp.seraph.jsade.sexpression.SExpression)
     */
    public void addChild(SExpression aExpression) {
        throw new UnsupportedOperationException();
    }

    /**
     * 
     * @see jp.seraph.jsade.sexpression.Node#addChild(java.lang.String)
     */

    public void addChild(String aValue) {
        throw new UnsupportedOperationException();
    }

    public void insertChild(SExpression value, int index) {
        throw new UnsupportedOperationException();
    }

    public void insertChild(String value, int index) {
        throw new UnsupportedOperationException();
    }

    /**
     * 
     * @see jp.seraph.jsade.sexpression.Node#getValue(java.lang.String)
     */
    public String getValue(String aName) {
        return mBaseNode.getValue(aName);
    }

    /**
     * 
     * @see java.lang.Iterable#iterator()
     */
    public Iterator<SExpression> iterator() {
        return mBaseNode.iterator();
    }

    /**
     * 
     * @see jp.seraph.jsade.sexpression.Node#allChildIsLeaf()
     */
    public boolean allChildIsLeaf() {
        return mBaseNode.allChildIsLeaf();
    }

    /**
     * 
     * @see jp.seraph.jsade.sexpression.Node#getValues(java.lang.String)
     */
    public String[] getValues(String aName) {
        return mBaseNode.getValues(aName);
    }

    /**
     * 
     * @see jp.seraph.jsade.sexpression.SExpression#accept(jp.seraph.jsade.sexpression.ExpressionVisitor)
     */
    public void accept(ExpressionVisitor aVisitor) {
        mBaseNode.accept(aVisitor);
    }

    /**
     * 
     * @see jp.seraph.jsade.sexpression.SExpression#childCount()
     */
    public int childCount() {
        return mBaseNode.childCount();
    }

    /**
     * 
     * @see jp.seraph.jsade.sexpression.SExpression#getChild(int)
     */
    public SExpression getChild(int aIndex) {
        return null;
    }

    /**
     * 
     * @see jp.seraph.jsade.sexpression.SExpression#getChildAsLeaf(int)
     */
    public Leaf getChildAsLeaf(int aIndex) {
        return mBaseNode.getChildAsLeaf(aIndex);
    }

    /**
     * 
     * @see jp.seraph.jsade.sexpression.SExpression#getChildAsNode(int)
     */
    public Node getChildAsNode(int aIndex) {
        return mBaseNode.getChildAsNode(aIndex);
    }

    /**
     * 
     * @see jp.seraph.jsade.sexpression.SExpression#getLeftString()
     */
    public String getLeftString() {
        return mBaseNode.getLeftString();
    }

    /**
     * 
     * @see jp.seraph.jsade.sexpression.SExpression#isLeaf()
     */
    public boolean isLeaf() {
        return false;
    }

    /**
     * 
     * @see jp.seraph.jsade.sexpression.SExpression#isNode()
     */
    public boolean isNode() {
        return true;
    }

}
